/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
  <file> uls_lf_sprintf.h </file>
  <brief>
    An upgraded version of varargs routines(sprintf,fprintf,printf, ..).
    This file is part of ULS, Unified Lexical Scheme.
  </brief>
  <author>
    Stanley J. Hong <babel96@gmail.com>, July 2011.
  </author>
*/
#ifndef __ULS_SPRINTF_H__
#define __ULS_SPRINTF_H__

#include "uls_type.h"
#include "csz_stream.h"

#include <stdarg.h>
#include <ctype.h>

#ifdef __cplusplus
extern "C" {
#endif

#define ULS_MAXSZ_NUMSTR    63
#define ULS_LF_PERCENT_NAMESIZ 3
#define ULS_LF_N_FILLCHS 16
#define ULS_LF_N_FILLSTR 64

#define ULS_LF_LEFT_JUSTIFIED     0x0001  /* left justified */
#define ULS_LF_ZEROPAD            0x0002  /* pad with zero */
#define ULS_LF_PLUS_PREFIX        0x0004  /* show plus */
#define ULS_LF_MINUS_PREFIX       0x0008  /* show minus */

#define ULS_LF_SPECIAL_CHAR       0x0010  /* 0x */
#define ULS_LF_DYNAMIC_WIDTH      0x0020
#define ULS_LF_DYNAMIC_PRECISION  0x0040

#define ULS_LF_BIN_PREFIX         0x0100
#define ULS_LF_HEX_PREFIX         0x0200
#define ULS_LF_PERCENT_E          0x0400
#define ULS_LF_PERCENT_G          0x0800

#define ULS_LF_DFL_FLOAT_PRECISION 6

#define ULS_LF_PERCPROC_object  0

#define ULS_LF_PERCPROC_s       1
#define ULS_LF_PERCPROC_c       2

#define ULS_LF_PERCPROC_d       3
#define ULS_LF_PERCPROC_u       4
#define ULS_LF_PERCPROC_f       5

#define ULS_LF_PERCPROC_ws      6
#define ULS_LF_PERCPROC_wc      7

#define ULS_LF_PERCPROC_Ld      8
#define ULS_LF_PERCPROC_Lu      9
#define ULS_LF_PERCPROC_Lf      10

#define ULS_LF_PERCPROC_ld      11
#define ULS_LF_PERCPROC_lu      12
#define ULS_LF_PERCPROC_lf      13

#define ULS_LF_PERCPROC_p       14

#define ULS_LF_PERCPROC_unknown 128

typedef char uls_lf_char_t;
typedef void (*uls_lf_puts_t)(void* dat, const uls_lf_char_t* str, int len);

typedef struct _uls_lf_name2proc uls_lf_name2proc_t;
typedef struct _uls_lf_convspec_table uls_lf_convspec_table_t;
typedef struct _uls_lf_map uls_lf_map_t;
typedef struct _uls_lf uls_lf_t;
typedef struct _uls_lf_context uls_lf_context_t;
typedef struct _uls_lf_convflag uls_lf_convflag_t;
typedef struct _uls_lf_csz uls_lf_csz_t;

typedef int (*uls_lf_convspec_t)(uls_lf_context_t* ctx, uls_lf_puts_t puts_proc);

typedef struct _buf4legacy buf4legacy_t;
struct _buf4legacy {
	unsigned int flags;
	uls_lf_char_t *buf, *bufptr;
	int buflen;
};

struct _uls_lf_convflag {
	uls_flags_t  flags;
	int    width, precision;
};

struct _uls_lf_name2proc {
	uls_lf_char_t name[ULS_LF_PERCENT_NAMESIZ+1];
	int l_name;
	uls_lf_convspec_t proc;
};

struct _uls_lf_convspec_table {
	uls_lf_name2proc_t  *proc_tab;
	int n_used, n_allocd;
};

struct _uls_lf_map {
	uls_lf_convspec_table_t linear;
	uls_lf_convspec_table_t sorted[ULS_LF_PERCENT_NAMESIZ];
};

struct _uls_lf {
	DECLARE_ULS_MUTEX(mtx);
	uls_lf_puts_t     uls_lf_puts;
	uls_lf_map_t convspec_map;
	csz_str_t zbuf1;
	csz_str_t zbuf2;
};

struct _uls_lf_context {
	void           *x_dat;
	uls_lf_convflag_t perfmt;
	void           *g_dat;
	va_list        args;
	csz_str_t      *numbuf1;
	csz_str_t      *numbuf2;
};

struct _uls_lf_csz {
	uls_lf_t *uls_lf;
	csz_str_t  csz;
};

#define get_perproc_table_ind(len) (len-1)

#define uls_lf_strcmp(a,b) strcmp((char *) (a), (char*) (b))
#define uls_lf_strncmp(a,b,n) strncmp((char *) (a), (char*) (b), n)
#define uls_lf_strlen(a) strlen((char *) (a))
#define uls_lf_strcpy(a,b) uls_strcpy((char *) (a), (char*) (b))
#define uls_lf_isdigit(c) isdigit(c)
#define uls_lf_isgraph(c) isgraph(c)

extern uls_lf_t *dfl_uls_lf;

uls_lf_t* uls_lf_create(uls_lf_puts_t puts_proc);
void uls_lf_init(uls_lf_t *uls_lf, uls_lf_puts_t puts_proc);
void uls_lf_deinit(uls_lf_t *uls_lf);
void uls_lf_destroy(uls_lf_t *uls_lf);

int uls_lf_register_convspec(uls_lf_t *uls_lf,
	const uls_lf_char_t* percent_name, uls_lf_convspec_t proc);
void uls_lf_change_puts(uls_lf_t *uls_lf, uls_lf_puts_t puts_proc);

int uls_lf_vxprintf(void* x_dat, uls_lf_t* uls_lf, void* g_dat, const uls_lf_char_t* fmt, va_list args);
int uls_lf_xprintf(void* x_dat, uls_lf_t* uls_lf, void* g_dat, const uls_lf_char_t* fmt, ...);

void uls_lf_csz_init(uls_lf_csz_t* bb, uls_lf_t* uls_lf);
void uls_lf_csz_reset(uls_lf_csz_t* bb, uls_lf_t* uls_lf);
void uls_lf_csz_deinit(uls_lf_csz_t* bb);
int  uls_lf_vzprintf(uls_lf_csz_t* bb, const uls_lf_char_t *fmt, va_list args);
int  uls_lf_zprintf(uls_lf_csz_t* bb, const uls_lf_char_t *fmt, ...);
int  uls_lf_zprintf_append(uls_lf_csz_t* bb, const uls_lf_char_t *fmt, ...);

int uls_lf_vxprintf_generic(uls_lf_t* uls_lf, void* dat, uls_lf_puts_t puts_proc,
		void* g_dat, const uls_lf_char_t* fmtstr, va_list args);

int uls_lf_puts_prefix(uls_lf_char_t* str, int flags);
void uls_lf_fill_ch(void *x_dat, uls_lf_puts_t puts_proc, uls_lf_char_t ch_fill, int n);
int uls_lf_fill_chars(void *x_dat, uls_lf_puts_t puts_proc,
	uls_lf_convflag_t* p, uls_lf_char_t* numstr, int l_numstr);
int uls_lf_fill_mbstr(void *x_dat, uls_lf_puts_t puts_proc,
	uls_lf_convflag_t* p, uls_lf_char_t* numstr, int l_numstr, int lw_numstr);

int uls_lf_number_u(uls_lf_char_t *numstr, unsigned int num, int base_shift);
int uls_lf_number_lu(uls_lf_char_t *numstr, unsigned long num, int base_shift);
int uls_lf_number_Lu(uls_lf_char_t *numstr, unsigned long long num, int base_shift);

#define ULS_LF_SHIFT_BASE_UNKNOWN -2
#define ULS_LF_SHIFT_BASE_OCT  -1
#define ULS_LF_SHIFT_BASE_DEC   0
#define ULS_LF_SHIFT_BASE_BIN   1
#define ULS_LF_SHIFT_BASE_HEX   4

void uls_lf_puts_csz(void* x_dat, const uls_lf_char_t* wrdptr, int wrdlen);
void uls_lf_puts_str(void* x_dat, const uls_lf_char_t* wrdptr, int wrdlen);
void uls_lf_puts_file(void* x_dat, const uls_lf_char_t* wrdptr, int wrdlen);
void uls_lf_puts_null(void* x_dat, const uls_lf_char_t* wrdptr, int wrdlen);

#ifdef __cplusplus
}
#endif

#endif
